home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume25 / pty4 / part07 < prev    next >
Encoding:
Text File  |  1992-02-18  |  43.2 KB  |  1,573 lines

  1. Newsgroups: comp.sources.unix
  2. From: brnstnd@nyu.edu (Dan Bernstein)
  3. Subject: v25i133: Generalized interface to pseudo-tty devices, Part07/09
  4. Sender: unix-sources-moderator@pa.dec.com
  5. Approved: vixie@pa.dec.com
  6.  
  7. Submitted-By: brnstnd@nyu.edu (Dan Bernstein)
  8. Posting-Number: Volume 25, Issue 133
  9. Archive-Name: pty4/part07
  10.  
  11. #! /bin/sh
  12. # This is a shell archive.  Remove anything before this line, then unpack
  13. # it by saving it into a file and typing "sh file".  To overwrite existing
  14. # files, type "sh file -c".  You can also feed this as standard input via
  15. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  16. # will see the following message at the end:
  17. #        "End of archive 7 (of 9)."
  18. # Contents:  SESS.draft2 ptymain.c sigsched.c
  19. # Wrapped by vixie@cognition.pa.dec.com on Wed Feb 19 13:35:06 1992
  20. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  21. if test -f 'SESS.draft2' -a "${1}" != "-c" ; then 
  22.   echo shar: Will not clobber existing file \"'SESS.draft2'\"
  23. else
  24. echo shar: Extracting \"'SESS.draft2'\" \(11273 characters\)
  25. sed "s/^X//" >'SESS.draft2' <<'END_OF_FILE'
  26. An introduction to session management
  27. Daniel J. Bernstein
  28. draft 2
  29. X10/4/91
  30. X
  31. X
  32. X1. Session basics
  33. X
  34. X          < session, n. ... 4. any period of activity. >
  35. X
  36. When a user sits down in front of a multi-user computer, gives his login
  37. name and password, and starts typing, he's begun a _session_. Within
  38. that session he might read mail, edit files, compile and run programs,
  39. and even play games. What happens if the screen explodes?
  40. X
  41. A typical UNIX system lets a user log in through a network, or over a
  42. phone connection between the user's modem and the computer's modem. But
  43. if the phone line suddenly becomes too noisy, or the network doesn't
  44. work, the user's connection may drop. The system will then terminate the
  45. login session. Any programs run by the user will be signalled that the
  46. connection was hung up. If they ask the user for input, they won't get
  47. any. If they produce output, the output will vanish.
  48. X
  49. Other operating systems are more helpful. VMS, for instance, keeps the
  50. session running inside the computer. When the user establishes another
  51. connection and logs in again, the computer asks if he'd like to
  52. reconnect to the original session. Programs started under the session
  53. won't notice what happened. This is a primitive form of _session
  54. management_. (It is also an abuse of terminology, as the ``session''---
  55. the ``period of activity''---really consists of two periods. On the
  56. other hand, from the point of view of the programs under the session,
  57. there hasn't been any interruption.)
  58. X
  59. This paper describes a session management system which the author has
  60. developed for BSD UNIX and its variants. In section 2 we describe the
  61. three fundamental operations making up the system. In section 3 we show
  62. how the system appears to novice users. In section 4 we give several
  63. examples of more complex session management techniques which cannot be
  64. performed under VMS.
  65. X
  66. X
  67. X2. sess, disconnect, reconnect
  68. X
  69. The session management system consists of three basic operations. To
  70. illustrate the operations we use pictures:
  71. X
  72. X   user ==== tty ==== csh                                         (1)
  73. X
  74. A double line, such as ====, represents a two-way flow of information.
  75. Here the user types characters, which the UNIX kernel processes inside a
  76. tty device and then sends to the user's shell, csh. What csh prints is
  77. then sent back through the tty to the user.
  78. X
  79. When csh starts a job, the picture changes:
  80. X
  81. X            ---------------
  82. X           /               \
  83. X   user ==== tty ==== csh      who
  84. X               \                |
  85. X                \              sort
  86. X                 \              |
  87. X                  ------------ more
  88. X
  89. Here the user has started a pipeline, who | sort | more. To simplify the
  90. illustration somewhat we pretend that all I/O from the pipeline is sent
  91. through the shell:
  92. X
  93. X   user ==== tty ==== csh ---- who
  94. X                         \      |
  95. X                          \    sort
  96. X                           \    |
  97. X                            -- more
  98. X
  99. A job consisting of only one process looks like this:
  100. X
  101. X   user ==== tty ==== csh ==== vi
  102. X
  103. If the user's connection dies, the tty effectively disappears:
  104. X
  105. X              csh ==== vi
  106. X
  107. Without a place to send input and output, csh and vi receive the HUP
  108. signal and die a messy death.
  109. X
  110. The first session management operation is sess. When the user, starting
  111. from picture (1), types ``sess ksh'', he creates a session:
  112. X
  113. X                   /------\      +------+
  114. X   user ==== tty ==== csh ==== | conn | ==== | sess | === ksh
  115. X                   \------/      +------+
  116. X
  117. The session consists of the square box, called the _master_ because it's
  118. in charge of session management, with ksh running below it. The session
  119. is connected to the rounded box, also called the _signaller_ because it
  120. signals csh when the session is finished. Normally both boxes are
  121. completely transparent, and the user can start jobs under the session:
  122. X
  123. X                   /------\      +------+
  124. X   user ==== tty ==== csh ==== | conn | ==== | sess | === ksh ==== vi     (2)
  125. X                   \------/      +------+
  126. X
  127. X(In fact, from ksh's point of view, the sess box looks just like a tty.
  128. It is actually a _pseudo-tty_, also known as a _pseudo-terminal_.
  129. XFurther discussion of pseudo-terminals is beyond the scope of this
  130. paper.)
  131. X
  132. What happens if the user's connection drops? As before, the original tty
  133. disappears, and csh sputters and dies. The signaller disappears too:
  134. X
  135. X                                 +------+
  136. X                                             | sess | === ksh ==== vi
  137. X                                 +------+
  138. X
  139. However, the session keeps running. sess doesn't mind being
  140. disconnected. It waits for a reconnect, as described below. Meanwhile,
  141. ksh doesn't have the slightest inkling that the connection is gone.
  142. X
  143. The user can in fact force a disconnect manually. This is the second
  144. fundamental operation. Starting from picture (2), if the user types
  145. X``disconnect'' to ksh, the connection will be severed:
  146. X
  147. X   user ==== tty ==== csh
  148. X
  149. X                             +------+
  150. X                                             | sess | === ksh ==== vi     (3)
  151. X                             +------+
  152. X
  153. The signaller exits quietly, and the user can now type commands to csh.
  154. X
  155. How does the user reconnect to a disconnected session? He uses the third
  156. fundamental operation, the reconnect command. The system assigns each
  157. session a name. If the user starts a new session, it might look like
  158. this:
  159. X
  160. X                   /------\      +------+
  161. X   user ==== tty ==== csh ==== | conn | ==== | sess | === qsh
  162. X                   \------/      +--p7--+
  163. X
  164. Here ``p7'' is this session's name. Say the disconnected session was
  165. named ``qb'':
  166. X
  167. X                   /------\      +------+
  168. X   user ==== tty ==== csh ==== | conn | ==== | sess | === qsh
  169. X                   \------/      +--p7--+
  170. X
  171. X                             +------+
  172. X                                             | sess | === ksh ==== vi
  173. X                             +--qb--+
  174. X
  175. If the user types ``reconnect qb'' to qsh, nothing happens immediately,
  176. but the signaller remembers his reconnect:
  177. X
  178. X                   /------\      +------+
  179. X   user ==== tty ==== csh ==== | conn | ==== | sess | === qsh
  180. X                   \-+qb+-/      +--p7--+
  181. X
  182. X                             +------+
  183. X                                             | sess | === ksh ==== vi
  184. X                             +--qb--+
  185. X
  186. As soon as session p7 exits (or is disconnected), the reconnect takes
  187. effect:
  188. X
  189. X                   /------\      +------+
  190. X   user ==== tty ==== csh ==== | conn | ==== | sess | === ksh ==== vi
  191. X                   \------/      +--qb--+
  192. X
  193. Now it's just as if session qb had been connected all along. The user
  194. can type commands to vi. If the connection disappears again, he can
  195. reconnect again, any number of times.
  196. X
  197. Why doesn't reconnect take effect immediately? There are several
  198. reasons. Perhaps the most important is that before reconnecting the user
  199. may want to terminate the currently connected session---or he may want
  200. to disconnect it, so that he can reconnect to it later. This reconnect
  201. interface doesn't force one choice or the other. The user may also want
  202. to perform some lengthy operations before reconnecting, and it's easier
  203. to schedule the reconnect once and do it at his leisure than to have to
  204. worry about the reconnect after all the operations. Finally, it is very
  205. simple to simulate an immediate reconnect using the above operations, as
  206. detailed in section 4.
  207. X
  208. X
  209. X3. Session management for users
  210. X
  211. Most users will never have to learn anything about the sess, disconnect,
  212. or reconnect commands. If a connection dies, its owner will be shown a
  213. message like this when he logs in again:
  214. X
  215. X  You have a disconnected session on /dev/ttyra, with these processes:
  216. X  USER       PID %CPU %MEM   SZ  RSS TT STAT START  TIME COMMAND
  217. X  shmoe    17790  0.0  0.9  176  504 ra T    12:47   0:01 vi paper.3
  218. X  shmoe    17331  0.0  0.7   72  384 ra I    12:31   0:00 -bin/csh (csh)
  219. X  shmoe    17330  0.0  0.5  104  264 ra S    12:31   0:00 pty -ds argv0 /bin/csh
  220. X  Would you like to reconnect to that session?
  221. X  If so, type its two-character extension, ra.
  222. X  To instead start a new session as usual, just press return:
  223. X
  224. The user will recognize the ``paper.3'' he was editing, type ra, and be
  225. reconnected to his session. The program which handles this is called
  226. X``sessmenu''. While perhaps not as friendly as the reconnect facilities
  227. under some operating systems, sessmenu isolates even novices from the
  228. trauma of losing important work.
  229. X
  230. All sessions also keep track of a long name assigned by the user. The
  231. X``sessname'' command displays or sets the current session name:
  232. X
  233. X   csh% sessname
  234. X   session p7
  235. X   csh% sessname 'writing net test program'
  236. X   csh% sessname
  237. X   session p7: writing net test program
  238. X   csh%
  239. X
  240. The user can see all his sessions with ``sesslist'':
  241. X
  242. X   csh% sesslist
  243. X   session p7 pid 16614 slave 16615 connected: writing net test program
  244. X   session ra pid 8045 slave 8046 disconnected: finishing up paper.3
  245. X   csh%
  246. X
  247. Two other useful commands are ``sesswho'', to show all sessions on the
  248. system and their owners, and ``sesswhere'', to show where those sessions
  249. are currently connected to. (The system administrator may disable these
  250. commands for security reasons.)
  251. X
  252. X
  253. X4. Advanced session management techniques
  254. X
  255. By combining the sess, disconnect, and reconnect commands in simple
  256. ways, a user can perform surprisingly powerful session operations. In
  257. this section we give some such combinations. The reader may enjoy
  258. drawing pictures to see how the commands work.
  259. X
  260. A user can reconnect to a disconnected session without finishing the
  261. current session with ``sess reconnect xx''. Another method for doing an
  262. immediate reconnect is ``reconnect xx; disconnect''. The second method
  263. is symmetric: if the original session was yy, the user can flip back and
  264. forth with
  265. X
  266. X   csh-yy% reconnect xx; disconnect
  267. X   ...
  268. X   ksh-xx% reconnect yy; disconnect
  269. X   ...
  270. X   csh-yy% reconnect xx; disconnect
  271. X
  272. and so on. To immediately reconnect to another session and finish the
  273. current session, he can use ``reconnect xx; exit'' or ``exec reconnect xx''.
  274. X
  275. Say a user is in the middle of something---running a crucial
  276. computation, perhaps, or ``talk''ing to another user---and decides to
  277. record what's happening. With sess, reconnect, and disconnect, he can do
  278. this without starting the program again:
  279. X
  280. X   [talk session going on, user types ^Z]
  281. X   Stopped
  282. X   csh% sess sh
  283. X   $ sessname; disconnect
  284. X   session rf
  285. X   csh% reconnect rf; disconnect
  286. X   reconnect: will connect to session rf when session p8 is done
  287. X   pty: info: reconnecting to rf
  288. X   pty: info: successfully connected to rf
  289. X   $ sess reconnect p8 | tee talk-record
  290. X   reconnect: will connect to session p8 when session q0 is done
  291. X   pty: info: reconnecting to p8
  292. X   pty: info: successfully connected to p8
  293. X   csh% fg
  294. X   [talk session continues as before]
  295. X
  296. Now everything in session p8 is recorded in talk-record. The recording
  297. is completely transparent and does not require that ``talk'' be
  298. terminated or restarted.
  299. X
  300. X
  301. X5. Where to find it
  302. X
  303. The session management system described here is freely available as part
  304. of the pty 4.0 package. pty 4.0 works on BSD-derived UNIX systems.
  305. X
  306. The author's session management model is based on Bellovin's ``Session
  307. Tty'' Manager [1], which is not as powerful as pty but is better
  308. integrated into the login system.
  309. X
  310. X
  311. References
  312. X
  313. X[1] Bellovin, S. M.  The ``Session Tty'' Manager. In USENIX Conference
  314. Proceedings, San Francisco, Summer 1988, 339-354.
  315. END_OF_FILE
  316. if test 11273 -ne `wc -c <'SESS.draft2'`; then
  317.     echo shar: \"'SESS.draft2'\" unpacked with wrong size!
  318. fi
  319. # end of 'SESS.draft2'
  320. fi
  321. if test -f 'ptymain.c' -a "${1}" != "-c" ; then 
  322.   echo shar: Will not clobber existing file \"'ptymain.c'\"
  323. else
  324. echo shar: Extracting \"'ptymain.c'\" \(16035 characters\)
  325. sed "s/^X//" >'ptymain.c' <<'END_OF_FILE'
  326. X#include <signal.h>
  327. X#include "sigsched.h"
  328. X#include "getoptquiet.h"
  329. X#include "ralloc.h"
  330. X#include "env.h"
  331. X#include "fmt.h"
  332. X#include "config/ptydir.h"
  333. X#include "config/ttyopts.h"
  334. X#include "config/ptyopts.h"
  335. X#include "config/posix.h"
  336. X#include "ptyget.h"
  337. X#include "ptytty.h"
  338. X#include "ptylogs.h"
  339. X#include "ptymisc.h"
  340. X#include "ptytexts.h"
  341. X#include "ptycomm.h"
  342. X#include "ptymaster.h"
  343. X#include "ptysigler.h"
  344. X#include "ptyerr.h"
  345. X#include "ptyslave.h"
  346. X#include "sesslog.h"
  347. X#include "sessconnlog.h"
  348. X
  349. X#define verbose 0, /*XXX*/
  350. X
  351. X/* XXX Exported to other files: */
  352. int flagxutmp = 0;
  353. int flagxwtmp = 0;
  354. X
  355. X/* Private flags: */
  356. static int flagxchown = 0;
  357. static int flagxexcl = 0; /* should be 1, but that'd break write & friends */
  358. static int flagxerrwo = 0; /* should be 1, but that'd break csh & more */
  359. static int flagxrandom = 1;
  360. static int flagxflowctl = 0; /* shouldn't have to exist */
  361. static int flagxonlysecure = 0; /* XXX: which one is right? */
  362. X
  363. static int flagreading = 1;
  364. static int flagdetached = 0;
  365. static int flagverbose = 1;
  366. static int flagjobctrl = 1;
  367. static int flagttymodes = 1;
  368. static int flagsameerr = 0;
  369. static int flagsession = 0;
  370. X
  371. static int flagpcbreak = 0; /* -pc, character-at-a-time */
  372. static int flagpnew = 1; /* -pd, new line discipline---traditionally off to start */
  373. static int flagpecho = 1; /* -pe, echo characters */
  374. static int flagpcrmod = 1; /* -pn, munge carriage returns */
  375. static int flagpraw = 0; /* -pr, raw mode */
  376. static int flagpcrt = 1; /* -ps, screen */
  377. static int flagp8bit = 1; /* -p8, 8-bit data path---traditionally off */
  378. X
  379. static int uid = -1; /* no harm in being safe */
  380. static char *username;
  381. static char *host;
  382. static char *remote;
  383. static char **program;
  384. X
  385. void setupsessionfiles(fdmty,fdsty,ext) /* XXX: move into master? */
  386. int fdmty;
  387. int fdsty;
  388. char *ext;
  389. X{
  390. X struct sesslog sl;
  391. X long t;
  392. X t = now();
  393. X if (utmp_on(ext,username,host,t) == -1)
  394. X  {
  395. X   warn("warning","cannot write utmp entry");
  396. X  }
  397. X if (wtmp_on(ext,username,host,t) == -1)
  398. X  {
  399. X   warn("warning","cannot write wtmp entry");
  400. X   utmp_off(ext,host,t); /* if this fails, too bad */
  401. X  }
  402. X sesslog_fill(&sl,ext,username,uid,getpid(),t);
  403. X if (sesslog(&sl) == -1)
  404. X  {
  405. X   warn("warning","cannot write sesslog entry");
  406. X   utmp_off(ext,host,t);
  407. X   wtmp_off(ext,host,t);
  408. X  }
  409. X /* sessconn will be handled later---remember, we start out disconnected! */
  410. X}
  411. X
  412. static int eachpty(ext)
  413. char *ext;
  414. X{
  415. X int fdtty;
  416. X
  417. X verbose("trying %c%c",ext[0],ext[1]);
  418. X
  419. X /* Note that there are several situations in which dissociation will fail. */
  420. X /* Fortunately, pty doesn't really care. */
  421. X fdtty = tty_getctrl();
  422. X /* note that we do this whether or not flagdetached */
  423. X if (tty_dissoc(fdtty) == -1)
  424. X   warn("warning","cannot dissociate from current tty");
  425. X if (fdtty != -1)
  426. X   close(fdtty);
  427. X return 0;
  428. X}
  429. X
  430. X/* for sigler if flagttymodes: */
  431. static struct ttymodes tmotty; /* original tty modes */
  432. static struct ttymodes tmottyzero; /* zero tty modes */
  433. X
  434. void startup(n)
  435. int n;
  436. X{
  437. X int pims[2];
  438. X int pimc[2];
  439. X int pid;
  440. X int fdmty;
  441. X int fdsty;
  442. X char ext[2];
  443. X int r1;
  444. X int r2;
  445. X char ch;
  446. X int fdcomm;
  447. X struct ttymodes ptymodes;
  448. X
  449. X r1 = 0;
  450. X r2 = 0;
  451. X if (flagxrandom)
  452. X  {
  453. X   r1 = getpid();
  454. X   r2 = 37 * getpid() + (int) now;
  455. X  }
  456. X
  457. X if (pipe(pims) == -1)
  458. X  {
  459. X   warn("fatal","cannot create internal pipe");
  460. X   die(DIE_IMPOSSIBLE);
  461. X  }
  462. X if (pipe(pimc) == -1)
  463. X  {
  464. X   warn("fatal","cannot create internal pipe");
  465. X   die(DIE_IMPOSSIBLE);
  466. X  }
  467. X
  468. X if (!flagdetached)
  469. X  {
  470. X   int fdtty;
  471. X
  472. X   if ((fdtty = tty_getctrl()) == -1)
  473. X    {
  474. X     warn("fatal","cannot find controlling tty; try -d?");
  475. X     die(DIE_NOCTTY);
  476. X    }
  477. X
  478. X   if (flagreading)
  479. X     if (tty_forcefg(fdtty) == -1)
  480. X      {
  481. X       warn("fatal","cannot force myself into foreground; try -R?");
  482. X       die(DIE_SETMODES);
  483. X      }
  484. X   /* The concept of !flagreading has a major problem: It's unsafe. We may */
  485. X   /* end up with someone else's tty modes. */
  486. X   if (tty_getmodes(fdtty,&ptymodes) == -1)
  487. X    {
  488. X     warn("fatal","cannot get modes of original tty");
  489. X     die(DIE_GETMODES);
  490. X    }
  491. X
  492. X   close(fdtty);
  493. X  }
  494. X else
  495. X  {
  496. X   tty_initmodes(&ptymodes);
  497. X   flagpcbreak |= 2; flagpnew |= 2; flagpecho |= 2;
  498. X   flagpcrmod |= 2; flagpraw |= 2; flagpcrt |= 2;
  499. X   flagp8bit |= 2;
  500. X  }
  501. X
  502. X tty_mungemodes(&ptymodes,
  503. X   flagpcbreak,flagpnew,flagpecho,flagpcrmod,flagpraw,flagpcrt,flagp8bit);
  504. X
  505. X switch(pid = fork())
  506. X  {
  507. X   case -1:
  508. X     warn("fatal","cannot fork master");
  509. X     die(DIE_FORK);
  510. X   case 0: /* master-slave */
  511. X#ifdef POSIX_SILLINESS
  512. X     if (setsid() == -1) /* cannot fail---we're not a pgrp leader after fork */
  513. X      {
  514. X       warn("fatal","cannot setsid");
  515. X       die(DIE_IMPOSSIBLE);
  516. X      }
  517. X#endif
  518. X     if (flagxonlysecure == -1)
  519. X      {
  520. X       if (getfreepty(&fdmty,&fdsty,ext,r1,r2,eachpty,flagxchown,1) == -1)
  521. X    {
  522. X         warn("fatal","no ptys available");
  523. X     ch = DIE_NOPTYS; write(pims[1],&ch,1); /* XXX */
  524. X         die(DIE_NOPTYS);
  525. X    }
  526. X      }
  527. X     else if (getfreepty(&fdmty,&fdsty,ext,r1,r2,eachpty,flagxchown,0) == -1)
  528. X      {
  529. X       warn("warning","no secure ptys available");
  530. X       if ((flagxonlysecure == 1) ||
  531. X         (getfreepty(&fdmty,&fdsty,ext,r1,r2,eachpty,flagxchown,1) == -1))
  532. X    {
  533. X         warn("fatal","no ptys available");
  534. X     ch = DIE_NOPTYS; write(pims[1],&ch,1); /* XXX */
  535. X         die(DIE_NOPTYS);
  536. X    }
  537. X      }
  538. X     if (flagverbose > 1)
  539. X      {
  540. X       char buf[50]; char *t; t = buf;
  541. X       t += fmt_strncpy(t,"using pty ",0);
  542. X       *t++ = ext[0]; *t++ = ext[1]; *t = 0;
  543. X       warn("info",buf);
  544. X      }
  545. X     switch(pid = fork())
  546. X      {
  547. X       case -1:
  548. X     warn("fatal","cannot fork slave");
  549. X     ch = DIE_FORK; write(pims[1],&ch,1); /* XXX */
  550. X     die(DIE_FORK);
  551. X       case 0: /* slave */
  552. X     signal(SIGTTOU,SIG_DFL); /* XXX: restore to original? */
  553. X     signal(SIGTTIN,SIG_DFL);
  554. X     signal(SIGPIPE,SIG_DFL);
  555. X         close(pims[0]);
  556. X     close(pims[1]);
  557. X     close(pimc[1]);
  558. X     close(fdmty);
  559. X     verbose("slave waiting...");
  560. X     if ((read(pimc[0],&ch,1) < 1) || (ch != 'k'))
  561. X      {
  562. X       warn("fatal","slave unable to read success code from master");
  563. X       die(1);
  564. X      }
  565. X     close(pimc[0]);
  566. X     verbose("slave starting...");
  567. X     slave(fdsty,ext,program,flagxerrwo,flagsameerr,uid,flagverbose,flagxexcl);
  568. X     return;
  569. X       default: /* master */
  570. X     if (setreuid(geteuid(),geteuid()) == -1)
  571. X      {
  572. X       warn("fatal","master unable to set its uids");
  573. X       ch = DIE_IMPOSSIBLE; write(pims[1],&ch,1); /* XXX */
  574. X       die(DIE_IMPOSSIBLE);
  575. X      }
  576. X         signal(SIGHUP,SIG_IGN);
  577. X         signal(SIGTSTP,SIG_IGN);
  578. X         signal(SIGINT,SIG_IGN);
  579. X         signal(SIGQUIT,SIG_IGN);
  580. X#ifdef TTY_WINDOWS
  581. X         signal(SIGWINCH,SIG_IGN);
  582. X#endif
  583. X         /* We are now completely isolated from tty and I/O signals. */
  584. X     verbose("master setting modes...");
  585. X     if (tty_setmodes(fdsty,&ptymodes) == -1)
  586. X      {
  587. X       warn("fatal","master unable to set modes of pseudo-tty");
  588. X       ch = DIE_SETMODES; write(pims[1],&ch,1); /* XXX */
  589. X       die(DIE_SETMODES);
  590. X      }
  591. X     if (chdir(PTYDIR) == -1)
  592. X      {
  593. X       warn("fatal","master cannot chdir to pty directory; is it set up correctly?");
  594. X       ch = DIE_PTYDIR; write(pims[1],&ch,1); /* XXX */
  595. X       die(DIE_PTYDIR);
  596. X      }
  597. X     if ((fdcomm = comm_read(ext,uid)) == -1)
  598. X      {
  599. X       warn("fatal","master cannot create socket; is pty dir set up correctly?");
  600. X       ch = DIE_ELSE; write(pims[1],&ch,1); /* XXX */
  601. X       die(DIE_ELSE);
  602. X      }
  603. X     setupsessionfiles(fdmty,fdsty,ext);
  604. X     if (write(pims[1],ext,2) != 2)
  605. X       ; /* wtf? can't break pipe---we haven't closed it! */
  606. X         close(pims[0]);
  607. X     close(pims[1]);
  608. X     close(pimc[0]);
  609. X     close(0);
  610. X     close(1);
  611. X     close(2); /* XXX: this leaves master without a good error fd */
  612. X     verbose("master starting...");
  613. X     master(fdcomm,fdmty,fdsty,ext,uid,pid,flagsession,pimc[1],username,flagxflowctl);
  614. X     return;
  615. X      }
  616. X     break;
  617. X   default: /* sigler */
  618. X     signal(SIGTTOU,SIG_DFL);
  619. X     signal(SIGTTIN,SIG_DFL);
  620. X     signal(SIGPIPE,SIG_DFL);
  621. X     if (chdir(PTYDIR) == -1)
  622. X      {
  623. X       warn("fatal","signaller cannot chdir to pty directory; is it set up?");
  624. X       die(DIE_PTYDIR);
  625. X      }
  626. X     close(pims[1]);
  627. X     close(pimc[0]);
  628. X     close(pimc[1]);
  629. X     switch(read(pims[0],ext,2))
  630. X      {
  631. X       case 1: /* XXX: master has already printed an error */
  632. X     die((int) ext[0]); /* XXX */
  633. X       case 2:
  634. X     break;
  635. X       default:
  636. X         warn("fatal","signaller cannot read success code from master");
  637. X         die(DIE_COMM);
  638. X     break;
  639. X      }
  640. X     if (flagttymodes) /* which implies flagreading && !flagdetached */
  641. X      {
  642. X       int fdtty;
  643. X
  644. X       if ((fdtty = tty_getctrl()) == -1)
  645. X    {
  646. X     warn("fatal","signaller cannot find controlling tty; try -T?");
  647. X     die(DIE_NOCTTY);
  648. X    }
  649. X       if (tty_getmodes(fdtty,&tmotty) == -1)
  650. X    {
  651. X     warn("fatal","signaller cannot get modes of original tty; try -T?");
  652. X     die(DIE_GETMODES);
  653. X    }
  654. X       tty_copymodes(&tmottyzero,&tmotty);
  655. X       tty_zeromode(&tmottyzero);
  656. X       if (tty_setmodes(fdtty,&tmottyzero) == -1)
  657. X    {
  658. X     tty_setmodes(fdtty,&tmotty); /* worth a try... */
  659. X     warn("fatal","signaller cannot set modes of original tty; try -T?");
  660. X     die(DIE_SETMODES);
  661. X    }
  662. X       close(fdtty);
  663. X      }
  664. X     close(pims[0]);
  665. X     sigler(ext,uid,pid,flagttymodes,&tmotty,&tmottyzero,flagreading,flagjobctrl,remote);
  666. X  }
  667. X}
  668. X
  669. static void outofmem(n)
  670. unsigned int n; /* number of bytes in failing malloc */
  671. X{
  672. X static char buf[] = "pty: fatal: out of memory\n";
  673. X /* XXX: if this is from master, we may die silently! */
  674. X bwrite(2,buf,sizeof(buf) - 1); /*XXXX*/
  675. X die(DIE_NOMEM);
  676. X}
  677. X
  678. static void usageerr(why,opt)
  679. int why;
  680. int opt;
  681. X{
  682. X static char buf[100];
  683. X char *t; t = buf;
  684. X switch(why)
  685. X  {
  686. X   case 'a':
  687. X     warn("fatal","what program do you want to run?");
  688. X     break;
  689. X   case 'p':
  690. X     t += fmt_strncpy(t,"unrecognized terminal mode option -p",0);
  691. X     *t++ = opt; *t = 0;
  692. X     warn("fatal",buf);
  693. X     break;
  694. X   case 'x':
  695. X     t += fmt_strncpy(t,"unrecognized security option -x",0);
  696. X     *t++ = opt; *t = 0;
  697. X     warn("fatal",buf);
  698. X     break;
  699. X   case 'u':
  700. X     t += fmt_strncpy(t,"unrecognized option -",0);
  701. X     *t++ = optproblem; *t = 0;
  702. X     warn("fatal",buf);
  703. X     break;
  704. X   case 'o':
  705. X     t += fmt_strncpy(t,"option -",0);
  706. X     *t++ = optproblem;
  707. X     t += fmt_strncpy(t," requires an argument",0);
  708. X     *t = 0;
  709. X     warn("fatal",buf);
  710. X     break;
  711. X  }
  712. X info(ptyusage);
  713. X die(DIE_USAGE);
  714. X}
  715. X
  716. main(argc,argv,envp)
  717. int argc;
  718. char *argv[];
  719. char *envp[];
  720. X{
  721. X int opt;
  722. X char *s;
  723. X int i;
  724. X char *proto;
  725. X char *protoremote;
  726. X
  727. X/* Stage 1: Initial security checks. */
  728. X if (forceopen(0) || forceopen(1) || forceopen(2) || forceopen(3))
  729. X  {
  730. X   warn("fatal","cannot set up open descriptors");
  731. X   die(DIE_SETUP);
  732. X  }
  733. X
  734. X/* Stage 2: Figure out userid and username. */
  735. X uid = getuid();
  736. X /* Preserve LOGNAME or USER if it's accurate. */
  737. X s = env_get("LOGNAME");
  738. X if (!s)
  739. X   s = env_get("USER");
  740. X if (s && (username2uid(s,&i) != -1) && (i == uid))
  741. X   username = s;
  742. X else
  743. X   uid2username(uid,&username);
  744. X
  745. X/* Stage 3: Guess at host and remote for system logs. */
  746. X host = 0;
  747. X remote = 0;
  748. X
  749. X proto = env_get("PROTO");
  750. X if (proto)
  751. X  {
  752. X   protoremote = ralloc(strlen(proto) + 10);
  753. X   if (protoremote)
  754. X    {
  755. X     s = protoremote;
  756. X     s += fmt_strncpy(s,proto,0);
  757. X     fmt_strncpy(s,"REMOTE",0);
  758. X     s = env_get(protoremote);
  759. X     rfree(protoremote);
  760. X     if (s)
  761. X      {
  762. X       remote = ralloc(strlen(proto) + strlen(s) + 10);
  763. X       if (remote)
  764. X    {
  765. X     char *t;
  766. X     t = remote;
  767. X     t += fmt_strncpy(t,proto,0);
  768. X     t += fmt_strncpy(t,":",0);
  769. X     fmt_strncpy(t,s,0);
  770. X     if (proto[0] == 'T' && proto[1] == 'C' && proto[2] == 'P' && !proto[3])
  771. X      { /* might as well assign host as well */
  772. X       t = remote;
  773. X       while (*t != '@') ++t; ++t;
  774. X       while (*t != '(') ++t; ++t;
  775. X       host = ralloc(strlen(t) + 4);
  776. X       if (host)
  777. X        {
  778. X         fmt_strncpy(host,t,0);
  779. X         t = host;
  780. X         while (*t != ')') ++t;
  781. X         *t = 0;
  782. X        }
  783. X      }
  784. X    }
  785. X       else
  786. X     remote = 0;
  787. X      }
  788. X    }
  789. X  }
  790. X if (!host)
  791. X   host = "pty4.0";
  792. X if (!remote)
  793. X   remote = "(unknown)";
  794. X
  795. X/* Stage 4: Process options. */
  796. X while ((opt = getopt(argc,argv,"ACHUVWqQvdDe3EjJsStTp:x:0rRh:O:")) != opteof)
  797. X   switch(opt)
  798. X    {
  799. X     case 'A': info(ptyauthor); die(DIE_USAGE); break;
  800. X     case 'C': info(ptycopyright); die(DIE_USAGE); break;
  801. X     case 'H': info(ptyhelp); die(DIE_USAGE); break;
  802. X     case 'U': info(ptyusage); die(DIE_USAGE); break;
  803. X     case 'V': info(ptyversion); die(DIE_USAGE); break;
  804. X     case 'W': info(ptywarranty); die(DIE_USAGE); break;
  805. X     case 'h': host = optarg; break;
  806. X     case 'O': remote = optarg; break;
  807. X     case 'q': flagverbose = 0; break;
  808. X     case 'Q': flagverbose = 1; break;
  809. X     case 'v': flagverbose = 2; break;
  810. X     case 'd': flagdetached = 1; flagjobctrl = 0; flagttymodes = 0; break;
  811. X     case 'D': flagdetached = 0; flagjobctrl = 1; flagttymodes = 1; break;
  812. X     case 'e': flagsameerr = 2; break;
  813. X     case '3': flagsameerr = 1; break;
  814. X     case 'E': flagsameerr = 0; break;
  815. X     case 'j': flagjobctrl = 1; break;
  816. X     case 'J': flagjobctrl = 0; break;
  817. X     case 'r': flagreading = 1; break;
  818. X     case 'R': flagreading = 0; break;
  819. X     case 's': flagsession = 1; flagxutmp = 1; break;
  820. X     case 'S': flagsession = 0; flagxutmp = 0; break;
  821. X     case 't': flagttymodes = 1; break;
  822. X     case 'T': flagttymodes = 0; break;
  823. X     case '0': flagsameerr = 2; flagsession = 0; flagttymodes = 0;
  824. X           flagxutmp = 0; /* XXX: also flagxwtmp = 0? */
  825. X           flagpcbreak = 3; flagpraw = 3; flagpecho = 2; flagpnew = 2;
  826. X           flagpcrmod = 2;
  827. X           /* XXXXXX: is this sensible behavior? */
  828. X           break;
  829. X     case 'p':
  830. X       while (opt = *(optarg++))
  831. X     switch(opt)
  832. X      {
  833. X       case 'c': flagpcbreak = 3; break;
  834. X       case 'C': flagpcbreak = 2; break;
  835. X       case 'd': flagpnew = 3; break;
  836. X       case 'D': flagpnew = 2; break;
  837. X       case 'e': flagpecho = 3; break;
  838. X       case 'E': flagpecho = 2; break;
  839. X       case '7': flagp8bit = 2; break;
  840. X       case '8': flagp8bit = 3; break;
  841. X       case 'n': flagpcrmod = 3; break;
  842. X       case 'N': flagpcrmod = 2; break;
  843. X       case 'r': flagpraw = 3; break;
  844. X       case 'R': flagpraw = 2; break;
  845. X       case 's': flagpcrt = 3; break;
  846. X       case 'S': flagpcrt = 2; break;
  847. X       case '0': flagpcbreak = 3; flagpraw = 3;
  848. X             flagpecho = 2; flagpnew = 2;
  849. X             flagpcrmod = 2;
  850. X             break;
  851. X       default: usageerr('p',opt); break;
  852. X      }
  853. X       break;
  854. X     case 'x':
  855. X       while (opt = *(optarg++))
  856. X     switch(opt)
  857. X      {
  858. X       case 'c': flagxchown = 1; break;
  859. X       case 'C': flagxchown = 0; break;
  860. X       case 'f': flagxflowctl = 1; break;
  861. X       case 'F': flagxflowctl = 0; break;
  862. X       case 'u': flagxutmp = 1; break;
  863. X       case 'U': flagxutmp = 0; break;
  864. X       case 'w': flagxwtmp = 1; break;
  865. X       case 'W': flagxwtmp = 0; break;
  866. X       case 'x': flagxexcl = 1; break;
  867. X       case 'X': flagxexcl = 0; break;
  868. X       case 'e': flagxerrwo = 1; break;
  869. X       case 'E': flagxerrwo = 0; break;
  870. X       case 'r': flagxrandom = 1; break;
  871. X       case 'R': flagxrandom = 0; break;
  872. X       case 's': flagxonlysecure = 1; break;
  873. X       case 'S': flagxonlysecure = 0; break;
  874. X       case 'i': flagxonlysecure = -1; break;
  875. X       default: usageerr('x',opt); break;
  876. X      }
  877. X       break;
  878. X     case '?':
  879. X     default:
  880. X       usageerr(argv[optind] ? 'u' : 'o',opt); break;
  881. X    }
  882. X argc -= optind;
  883. X argv += optind;
  884. X
  885. X program = argv;
  886. X if (!*program)
  887. X   usageerr('a',opt);
  888. X
  889. X/* Stage 5: Munge options. */
  890. X
  891. X#ifdef MUSTNOT_SESSION
  892. X if (flagsession) { flagsession = 0; warn("info","-s forced off"); }
  893. X#endif
  894. X#ifdef MUSTNOT_UTMPHOST
  895. X host = "pty4.0";
  896. X#endif
  897. X#ifdef MUSTNOT_UTMP
  898. X if (flagxutmp) { flagxutmp = 0; warn("info","-xu forced off"); }
  899. X#endif
  900. X#ifdef MUSTNOT_WTMP
  901. X if (flagxwtmp) { flagxwtmp = 0; warn("info","-xw forced off"); }
  902. X#endif
  903. X#ifdef MUSTNOT_CHOWN
  904. X if (flagxchown) { flagxchown = 0; warn("info","-xc forced off"); }
  905. X#endif
  906. X
  907. X if (flagsession) flagsameerr = 0;
  908. X if (flagdetached) flagttymodes = 0;
  909. X if (!flagreading) flagttymodes = 0;
  910. X
  911. X if (!flagsession)
  912. X  {
  913. X   sesslog_disable();
  914. X   sessconnlog_disable();
  915. X  }
  916. X if (!flagverbose)
  917. X   warn_disable();
  918. X
  919. X/* Stage 6: Set up signals and enter sigsched. */
  920. X rallocneverfail(outofmem);
  921. X
  922. X ss_addsig(SIGCHLD);
  923. X ss_addsig(SIGHUP);
  924. X ss_addsig(SIGTSTP);
  925. X ss_addsig(SIGINT);
  926. X ss_addsig(SIGQUIT);
  927. X#ifdef TTY_WINDOWS
  928. X ss_addsig(SIGWINCH);
  929. X#endif
  930. X signal(SIGTTOU,SIG_IGN);
  931. X signal(SIGTTIN,SIG_IGN);
  932. X signal(SIGPIPE,SIG_IGN);
  933. X
  934. X ss_schedonce(ss_asap(),startup,0);
  935. X ss_exec();
  936. X die(0);
  937. X}
  938. END_OF_FILE
  939. if test 16035 -ne `wc -c <'ptymain.c'`; then
  940.     echo shar: \"'ptymain.c'\" unpacked with wrong size!
  941. fi
  942. # end of 'ptymain.c'
  943. fi
  944. if test -f 'sigsched.c' -a "${1}" != "-c" ; then 
  945.   echo shar: Will not clobber existing file \"'sigsched.c'\"
  946. else
  947. echo shar: Extracting \"'sigsched.c'\" \(13289 characters\)
  948. sed "s/^X//" >'sigsched.c' <<'END_OF_FILE'
  949. X/* sigsched.c, sigsched.h: signal-schedule thread library
  950. Daniel J. Bernstein, brnstnd@nyu.edu.
  951. Depends on ralloc.h, sod.h, config/fdsettrouble.h.
  952. Requires BSDish environment: reliable signals, sig{vec,block,setmask}, select.
  953. X9/1/91: Added worst-case fdset, FD_ZERO, etc. definitions.
  954. X8/25/91: sigsched 1.1, public domain.
  955. X8/25/91: Fixed bug that sigs[sched->blah].r didn't force instant timeout.
  956. X8/25/91: Fixed bug that if select() returned -1 then fds were still checked.
  957. X7/21/91: Changed forever to a 1-hour wakeup.
  958. X7/19/91: Added isopen() to fix bug in case of bad descriptor.
  959. X7/18/91: Baseline. sigsched 1.0, public domain.
  960. No known patent problems.
  961. X
  962. Documentation in sigsched.3.
  963. X
  964. XXXX: how well do we clean up upon ss_exec() exit?
  965. X
  966. X*/
  967. X
  968. X#include <sys/types.h>
  969. X#include <sys/param.h>
  970. X#include <sys/time.h>
  971. X#include <signal.h>
  972. X#include <errno.h>
  973. X#include <fcntl.h>
  974. extern int errno;
  975. X#include "config/fdsettrouble.h"
  976. X#include "sigsched.h"
  977. X#include "ralloc.h"
  978. X#include "sod.h"
  979. X
  980. X/* XXX: should restore signal set exactly after ss_exec returns */
  981. X
  982. typedef int sigc_set; /*XXX */
  983. X
  984. X#define sigc_ismember(x,i) (*(x) & (1 << ((i) - 1)))
  985. X#define sigc_addset(x,i) (*(x) |= (1 << ((i) - 1)))
  986. X#define sigc_emptyset(x) (*(x) = 0)
  987. X
  988. X/*       sigprocmask(SIG_UNBLOCK,xxxx,(sigc_set *) 0); */
  989. X#define sigc_unblock(x) (sigsetmask(sigblock(0) & ~*(x)))
  990. X/*       sigprocmask(SIG_BLOCK,xxxx,(sigc_set *) 0); */
  991. X#define sigc_block(x) (sigblock(*(x)))
  992. X
  993. X#ifndef NSIG
  994. X#define NSIG 64 /* it's not as if any sane system has more than 32 */
  995. X#endif
  996. X
  997. X#define NUMSIGS NSIG
  998. X
  999. X#ifndef FD_SETSIZE
  1000. X#define FD_SETSIZE 256
  1001. X#endif
  1002. X
  1003. X#define NUMFDS FD_SETSIZE /* if select() can't handle it, we can't either */
  1004. X
  1005. X#ifdef LACKING_FD_ZERO
  1006. X#define NFDBITS    (sizeof(fd_mask) * NBBY)
  1007. X#define    FD_SET(n,p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
  1008. X#define    FD_ISSET(n,p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
  1009. X#define FD_ZERO(p) bzero((caddr_t)(p),sizeof(*(p)))
  1010. X#endif
  1011. X
  1012. X#ifdef DESPERATION_FD_SET
  1013. X#undef NFDBITS
  1014. X#undef FD_SET
  1015. X#undef FD_ISSET
  1016. X#undef FD_ZERO
  1017. X#undef fd_set
  1018. X#define fd_set long
  1019. X#define FD_SET(n,p) ((*p) |= (1 << (n)))
  1020. X#define FD_ISSET(n,p) ((*p) & (1 << (n)))
  1021. X#define FD_ZERO(p) (*p = 0L)
  1022. X#endif
  1023. X
  1024. X#define ASAP 1
  1025. X#define SIGNAL 2
  1026. X#define READ 3
  1027. X#define WRITE 4
  1028. X#define EXCEPT 5
  1029. X#define JUNK 6
  1030. X#define EXTERN 7
  1031. X
  1032. typedef struct { ss_sig s; int r; } ss_sigplus;
  1033. X
  1034. static ss_sigplus asap;
  1035. static ss_sigplus sigs[NUMSIGS];
  1036. static ss_sigplus reads[NUMFDS];
  1037. static ss_sigplus writes[NUMFDS];
  1038. static ss_sigplus excepts[NUMFDS];
  1039. static ss_sigplus junk; /* special case for internal use */
  1040. X
  1041. static void initsigs()
  1042. X{
  1043. X int i;
  1044. X asap.s.type = ASAP; asap.s.u.n = 0; asap.r = 0;
  1045. X for (i = 0;i < NUMSIGS;++i)
  1046. X  { sigs[i].s.type = SIGNAL; sigs[i].s.u.n = i; sigs[i].r = 0; }
  1047. X for (i = 0;i < NUMFDS;++i)
  1048. X  { reads[i].s.type = READ; reads[i].s.u.n = i; reads[i].r = 0; }
  1049. X for (i = 0;i < NUMFDS;++i)
  1050. X  { writes[i].s.type = WRITE; writes[i].s.u.n = i; writes[i].r = 0; }
  1051. X for (i = 0;i < NUMFDS;++i)
  1052. X  { excepts[i].s.type = EXCEPT; excepts[i].s.u.n = i; excepts[i].r = 0; }
  1053. X junk.s.type = JUNK; junk.s.u.n = 0; junk.r = 0;
  1054. X}
  1055. X
  1056. ss_sig *ss_asap()
  1057. X{ return &(asap.s); }
  1058. X#define OKsig(i) ((i >= 0) && (i < NUMSIGS))
  1059. ss_sig *ss_signal(i) int i;
  1060. X{ if (!OKsig(i)) return 0; return &(sigs[i].s); }
  1061. X#define OKfd(fd) ((fd >= 0) && (fd < NUMFDS))
  1062. ss_sig *ss_sigread(fd) int fd;
  1063. X{ if (!OKfd(fd)) return 0; return &(reads[fd].s); }
  1064. ss_sig *ss_sigwrite(fd) int fd;
  1065. X{ if (!OKfd(fd)) return 0; return &(writes[fd].s); }
  1066. ss_sig *ss_sigexcept(fd) int fd;
  1067. X{ if (!OKfd(fd)) return 0; return &(excepts[fd].s); }
  1068. X
  1069. void ss_externsetsig(sig,x)
  1070. ss_sig *sig;
  1071. ss_extern *x;
  1072. X{
  1073. X sig->type = EXTERN;
  1074. X sig->u.c = (char *) x;
  1075. X}
  1076. X
  1077. struct sched
  1078. X {
  1079. X  ss_sig *sig;
  1080. X  ss_thread *t;
  1081. X  union { ss_id i; ss_idptr p; } id;
  1082. X  int flagi;
  1083. X  int wait;
  1084. X }
  1085. X;
  1086. X
  1087. SODdecl(schedlist,struct sched);
  1088. X
  1089. static schedlist schedhead = 0;
  1090. static int schednum = 0;
  1091. static int schedjunked = 0;
  1092. static int numwait = 0;
  1093. X
  1094. void ss_forcewait()
  1095. X{
  1096. X ++numwait;
  1097. X}
  1098. X
  1099. void ss_unforcewait()
  1100. X{
  1101. X --numwait;
  1102. X}
  1103. X
  1104. int ss_schedvwait(sig,t,flagi,i,p,wait)
  1105. ss_sig *sig;
  1106. ss_thread *t;
  1107. int flagi;
  1108. ss_id i;
  1109. ss_idptr p;
  1110. int wait;
  1111. X{
  1112. X schedlist s;
  1113. X
  1114. X if (sig->type == EXTERN)
  1115. X  {
  1116. X   ss_extern *x;
  1117. X   x = (ss_extern *) sig->u.c;
  1118. X   return x->sched(x,t,flagi,i,p,wait);
  1119. X  }
  1120. X s = SODalloc(schedlist,s,ralloc);
  1121. X if (!s)
  1122. X   return -1;
  1123. X SODdata(s).sig = sig;
  1124. X SODdata(s).t = t;
  1125. X if (SODdata(s).flagi = flagi)
  1126. X   SODdata(s).id.i = i;
  1127. X else
  1128. X   SODdata(s).id.p = p;
  1129. X SODdata(s).wait = wait;
  1130. X SODpush(schedhead,s);
  1131. X ++schednum;
  1132. X if (wait)
  1133. X   ++numwait;
  1134. X return 0;
  1135. X}
  1136. X
  1137. int ss_schedwait(sig,t,i,wait)
  1138. ss_sig *sig;
  1139. ss_thread *t;
  1140. ss_id i;
  1141. int wait;
  1142. X{
  1143. X return ss_schedvwait(sig,t,1,i,(ss_idptr) 0,wait);
  1144. X}
  1145. X
  1146. int ss_sched(sig,t,i)
  1147. ss_sig *sig;
  1148. ss_thread *t;
  1149. ss_id i;
  1150. X{
  1151. X return ss_schedvwait(sig,t,1,i,(ss_idptr) 0,0);
  1152. X}
  1153. X
  1154. struct oncestuff { ss_sig *sig; ss_thread *t; ss_id i; } ;
  1155. X/* XXX: this is the same as some other struct */
  1156. X
  1157. static void once(p)
  1158. ss_idptr p;
  1159. X{
  1160. X struct oncestuff *os;
  1161. X os = (struct oncestuff *) p;
  1162. X if (ss_unschedv(os->sig,once,0,0,p) == -1)
  1163. X   ; /* impossible */
  1164. X os->t(os->i);
  1165. X RFREE(os);
  1166. X}
  1167. X
  1168. int ss_schedonce(sig,t,i)
  1169. ss_sig *sig;
  1170. ss_thread *t;
  1171. ss_id i;
  1172. X{
  1173. X struct oncestuff *os;
  1174. X
  1175. X os = (struct oncestuff *) ralloc(sizeof(struct oncestuff));
  1176. X if (!os)
  1177. X   return -1;
  1178. X os->sig = sig; os->t = t; os->i = i;
  1179. X return ss_schedvwait(sig,once,0,0,(ss_idptr) os,1);
  1180. X}
  1181. X
  1182. X/* XXX: could rallocinstall() this, if it has the recvhead() test */
  1183. X
  1184. static int schedcleanup()
  1185. X{
  1186. X schedlist s;
  1187. X schedlist t;
  1188. X schedlist sprev;
  1189. X
  1190. X/*  if (recvhead) return 0;  XXX: needs recvhead in scope */
  1191. X
  1192. X if (!schedjunked)
  1193. X   return 0;
  1194. X
  1195. X sprev = 0;
  1196. X s = schedhead;
  1197. X while (s)
  1198. X  {
  1199. X   if (SODdata(s).sig == &(junk.s))
  1200. X    {
  1201. X     if (sprev)
  1202. X      {
  1203. X       SODpop(SODnext(sprev),t); /* XXX: not part of official sod interface */
  1204. X       s = SODnext(sprev);
  1205. X      }
  1206. X     else
  1207. X      {
  1208. X       SODpop(s,t);
  1209. X       schedhead = s;
  1210. X      }
  1211. X     SODfree(t,rfree);
  1212. X     --schednum;
  1213. X     --schedjunked;
  1214. X    }
  1215. X   else
  1216. X    {
  1217. X     sprev = s;
  1218. X     s = SODnext(s);
  1219. X    }
  1220. X  }
  1221. X
  1222. X/* schednum -= schedjunked; now done dynamically inside loop */
  1223. X/* schedjunked = 0; */
  1224. X return 1;
  1225. X}
  1226. X
  1227. static void nothing(id)
  1228. ss_id id;
  1229. X{
  1230. X ;
  1231. X}
  1232. X
  1233. int ss_unschedv(sig,t,flagi,i,p)
  1234. ss_sig *sig;
  1235. ss_thread *t;
  1236. int flagi;
  1237. ss_id i;
  1238. ss_idptr p;
  1239. X{
  1240. X schedlist s;
  1241. X
  1242. X if (sig->type == EXTERN)
  1243. X  {
  1244. X   ss_extern *x;
  1245. X   x = (ss_extern *) sig->u.c;
  1246. X   return x->unsched(x,t,flagi,i,p);
  1247. X  }
  1248. X for (s = schedhead;s;s = SODnext(s))
  1249. X   if (SODdata(s).sig == sig && SODdata(s).t == t)
  1250. X     if (SODdata(s).flagi == flagi)
  1251. X       if (flagi ? (SODdata(s).id.i == i) : (SODdata(s).id.p == p))
  1252. X        {
  1253. X         SODdata(s).sig = &(junk.s);
  1254. X         SODdata(s).t = nothing; /* just in case */
  1255. X         if (SODdata(s).wait)
  1256. X           --numwait;
  1257. X         SODdata(s).wait = 0;
  1258. X         ++schedjunked;
  1259. X         return 0;
  1260. X        }
  1261. X return 1;
  1262. X}
  1263. X
  1264. int ss_unsched(sig,t,i)
  1265. ss_sig *sig;
  1266. ss_thread *t;
  1267. ss_id i;
  1268. X{
  1269. X return ss_unschedv(sig,t,1,i,(ss_idptr) 0);
  1270. X}
  1271. X
  1272. static struct timeval timeout;
  1273. static struct timeval instant = { 0, 0 };
  1274. static struct timeval forever = { 3600, 0 };
  1275. X  /* XXX: talk to me */
  1276. X
  1277. static void handle(i)
  1278. int i;
  1279. X{
  1280. X timeout = instant; /* XXX: structure copying */
  1281. X sigs[i].r = 1;
  1282. X}
  1283. X
  1284. static sigc_set sigstorage;
  1285. static sigc_set *xxxx = 0;
  1286. X
  1287. int ss_addsig(i)
  1288. int i;
  1289. X{
  1290. X if (!OKsig(i))
  1291. X   return -1;
  1292. X if (!xxxx)
  1293. X  {
  1294. X   xxxx = &sigstorage;
  1295. X   sigc_emptyset(xxxx);
  1296. X  }
  1297. X sigc_addset(xxxx,i);
  1298. X return 0;
  1299. X}
  1300. X
  1301. static int isopen(fd)
  1302. int fd;
  1303. X{
  1304. X /* XXX: should call this only if select() fails */
  1305. X return fcntl(fd,F_GETFL,0) != -1;
  1306. X}
  1307. X
  1308. SODdecl(recvlist,schedlist);
  1309. X
  1310. int ss_exec()
  1311. X{
  1312. X int i;
  1313. X struct sigvec sv;
  1314. X recvlist recvhead;
  1315. X recvlist temp;
  1316. X schedlist sch;
  1317. X
  1318. X initsigs();
  1319. X
  1320. X if (xxxx)
  1321. X  {
  1322. X   sigc_block(xxxx);
  1323. X
  1324. X   sv.sv_handler = handle;
  1325. X   sv.sv_mask = *xxxx; /* so handle won't interrupt itself */
  1326. X   sv.sv_flags = 0;
  1327. X
  1328. X   /* XXX: Does anyone but me find it absolutely idiotic that POSIX
  1329. X      doesn't provide a way to get each member of a signal set in turn? */
  1330. X   for (i = 0;i < NUMSIGS;i++)
  1331. X    {
  1332. X     if (sigc_ismember(xxxx,i))
  1333. X       if (sigvec(i,&sv,(struct sigvec *) 0) == -1) /*XXX: really trash orig? */
  1334. X     ; /* not our problem */
  1335. X    }
  1336. X  }
  1337. X
  1338. X recvhead = 0;
  1339. X
  1340. X while (numwait)
  1341. X  {
  1342. X   if (recvhead)
  1343. X    {
  1344. X     int w;
  1345. X     SODpop(recvhead,temp);
  1346. X     sch = SODdata(temp);
  1347. X
  1348. X/* This is the only section where we call user code. */
  1349. X#define DOIT \
  1350. if (SODdata(sch).flagi) \
  1351. X  SODdata(sch).t(SODdata(sch).id.i); \
  1352. else \
  1353. X  SODdata(sch).t(SODdata(sch).id.p);
  1354. X
  1355. X     switch(SODdata(sch).sig->type)
  1356. X      {
  1357. X       case JUNK:
  1358. X     break; /* has been unscheduled while waiting on the receive list */
  1359. X       case ASAP:
  1360. X     DOIT
  1361. X     break;
  1362. X       case READ:
  1363. X     if (reads[w = SODdata(sch).sig->u.n].r)
  1364. X       DOIT
  1365. X     reads[w].r = 0;
  1366. X     break;
  1367. X       case WRITE:
  1368. X     if (writes[w = SODdata(sch).sig->u.n].r)
  1369. X       DOIT
  1370. X     writes[w].r = 0;
  1371. X     break;
  1372. X       case EXCEPT:
  1373. X     if (excepts[w = SODdata(sch).sig->u.n].r)
  1374. X       DOIT
  1375. X     excepts[w].r = 0;
  1376. X     break;
  1377. X       case SIGNAL:
  1378. X     if (sigs[w = SODdata(sch).sig->u.n].r)
  1379. X       DOIT
  1380. X     sigs[w].r = 0;
  1381. X       /* ``after the end of the last...'' */
  1382. X     break;
  1383. X       case EXTERN:
  1384. X     /* by definition, an external library handles this */
  1385. X     break;
  1386. X       default: /* XXX: huh? */
  1387. X     ;
  1388. X      }
  1389. X     SODfree(temp,rfree);
  1390. X    }
  1391. X   else
  1392. X    {
  1393. X     schedlist sp;
  1394. X     static fd_set rfds;
  1395. X     static fd_set wfds;
  1396. X     static fd_set efds;
  1397. X     static int maxfd;
  1398. X     int r;
  1399. X
  1400. X     if (schedjunked > 100)
  1401. X       if (schednum / schedjunked < 3)
  1402. X         (void) schedcleanup(); /* now's as good a time as any */
  1403. X
  1404. X     timeout = forever;
  1405. X     FD_ZERO(&rfds);
  1406. X     FD_ZERO(&wfds);
  1407. X     FD_ZERO(&efds);
  1408. X     maxfd = -1;
  1409. X
  1410. X     for (sp = schedhead;sp;sp = SODnext(sp))
  1411. X      {
  1412. X       switch(SODdata(sp).sig->type)
  1413. X    {
  1414. X     case JUNK:
  1415. X       break;
  1416. X     case ASAP:
  1417. X       timeout = instant;
  1418. X       break;
  1419. X     case SIGNAL:
  1420. X       if (sigs[SODdata(sp).sig->u.n].r)
  1421. X         timeout = instant;
  1422. X       break;
  1423. X     case READ:
  1424. X       if (isopen(SODdata(sp).sig->u.n))
  1425. X         FD_SET(SODdata(sp).sig->u.n,&rfds);
  1426. X       if (SODdata(sp).sig->u.n > maxfd)
  1427. X         maxfd = SODdata(sp).sig->u.n;
  1428. X       break;
  1429. X     case WRITE:
  1430. X       if (isopen(SODdata(sp).sig->u.n))
  1431. X         FD_SET(SODdata(sp).sig->u.n,&wfds);
  1432. X       if (SODdata(sp).sig->u.n > maxfd)
  1433. X         maxfd = SODdata(sp).sig->u.n;
  1434. X       break;
  1435. X     case EXCEPT:
  1436. X       if (isopen(SODdata(sp).sig->u.n))
  1437. X         FD_SET(SODdata(sp).sig->u.n,&efds);
  1438. X       if (SODdata(sp).sig->u.n > maxfd)
  1439. X         maxfd = SODdata(sp).sig->u.n;
  1440. X       break;
  1441. X     case EXTERN:
  1442. X       break;
  1443. X     default: /*XXX: huh? */
  1444. X       break;
  1445. X    }
  1446. X      }
  1447. X
  1448. X     if (xxxx)
  1449. X       sigc_unblock(xxxx);
  1450. X     /* This is the only section where handle() can be called. */
  1451. X     /* XXX: If maxfd == -1, this select functions as a pause. */
  1452. X     /* XXX: If maxfd == -1 and timeout is instant, should skip select. */
  1453. X     /* XXX: Random bug of note: Real BSD systems will say that the
  1454. X        fd is writable as soon as a network connect() fails. The first
  1455. X    I/O will show the error (though it's rather stupid that you
  1456. X    can't find out the error without doing I/O). What does Ultrix
  1457. X    4.1 do? It pauses for 75 seconds. Dolts. */
  1458. X     r = select(maxfd + 1,&rfds,&wfds,&efds,&timeout);
  1459. X       /* XXX: does this necessarily prevent timeout race conditions? */
  1460. X     if (xxxx)
  1461. X       sigc_block(xxxx);
  1462. X
  1463. X     if (r == -1)
  1464. X      {
  1465. X       FD_ZERO(&rfds);
  1466. X       FD_ZERO(&wfds);
  1467. X       FD_ZERO(&efds);
  1468. X       switch(errno)
  1469. X        {
  1470. X         case EINTR: /* fine, this will happen on any signal */ break;
  1471. X         case EBADF: /* who knows? */ break;
  1472. X         case EINVAL: /* simply impossible */ break;
  1473. X         default: /*XXX*/ ;
  1474. X     /* well, that was real useful */
  1475. X        }
  1476. X      }
  1477. X
  1478. X     for (sp = schedhead;sp;sp = SODnext(sp))
  1479. X      {
  1480. X       switch(SODdata(sp).sig->type) 
  1481. X    {
  1482. X     case JUNK:
  1483. X       break;
  1484. X     case ASAP:
  1485. X           temp = SODalloc(recvlist,temp,ralloc);
  1486. X           if (!temp)
  1487. X             return -1; /*XXX*/
  1488. X       SODdata(temp) = sp;
  1489. X           SODpush(recvhead,temp);
  1490. X       break;
  1491. X     case SIGNAL:
  1492. X       if (sigs[SODdata(sp).sig->u.n].r)
  1493. X        {
  1494. X             temp = SODalloc(recvlist,temp,ralloc);
  1495. X             if (!temp)
  1496. X               return -1; /*XXX*/
  1497. X         SODdata(temp) = sp;
  1498. X             SODpush(recvhead,temp);
  1499. X        }
  1500. X       break;
  1501. X     case READ:
  1502. X       if (FD_ISSET(SODdata(sp).sig->u.n,&rfds))
  1503. X        {
  1504. X         FD_CLR(SODdata(sp).sig->u.n,&rfds);
  1505. X         reads[SODdata(sp).sig->u.n].r = 1;
  1506. X             temp = SODalloc(recvlist,temp,ralloc);
  1507. X             if (!temp)
  1508. X               return -1; /*XXX*/
  1509. X         SODdata(temp) = sp;
  1510. X             SODpush(recvhead,temp);
  1511. X        }
  1512. X       break;
  1513. X     case WRITE:
  1514. X       if (FD_ISSET(SODdata(sp).sig->u.n,&wfds))
  1515. X        {
  1516. X         FD_CLR(SODdata(sp).sig->u.n,&wfds);
  1517. X         writes[SODdata(sp).sig->u.n].r = 1;
  1518. X             temp = SODalloc(recvlist,temp,ralloc);
  1519. X             if (!temp)
  1520. X               return -1; /*XXX*/
  1521. X         SODdata(temp) = sp;
  1522. X             SODpush(recvhead,temp);
  1523. X        }
  1524. X       break;
  1525. X     case EXCEPT:
  1526. X       if (FD_ISSET(SODdata(sp).sig->u.n,&efds))
  1527. X        {
  1528. X         FD_CLR(SODdata(sp).sig->u.n,&efds);
  1529. X         excepts[SODdata(sp).sig->u.n].r = 1;
  1530. X             temp = SODalloc(recvlist,temp,ralloc);
  1531. X             if (!temp)
  1532. X               return -1; /*XXX*/
  1533. X         SODdata(temp) = sp;
  1534. X             SODpush(recvhead,temp);
  1535. X        }
  1536. X       break;
  1537. X     case EXTERN:
  1538. X       break;
  1539. X     default:
  1540. X       break;
  1541. X    }
  1542. X      }
  1543. X    }
  1544. X  }
  1545. X if (xxxx)
  1546. X   sigc_unblock(xxxx);
  1547. X   /* XXX: should put this at other returns as well */
  1548. X return 0;
  1549. X}
  1550. END_OF_FILE
  1551. if test 13289 -ne `wc -c <'sigsched.c'`; then
  1552.     echo shar: \"'sigsched.c'\" unpacked with wrong size!
  1553. fi
  1554. # end of 'sigsched.c'
  1555. fi
  1556. echo shar: End of archive 7 \(of 9\).
  1557. cp /dev/null ark7isdone
  1558. MISSING=""
  1559. for I in 1 2 3 4 5 6 7 8 9 ; do
  1560.     if test ! -f ark${I}isdone ; then
  1561.     MISSING="${MISSING} ${I}"
  1562.     fi
  1563. done
  1564. if test "${MISSING}" = "" ; then
  1565.     echo You have unpacked all 9 archives.
  1566.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1567. else
  1568.     echo You still need to unpack the following archives:
  1569.     echo "        " ${MISSING}
  1570. fi
  1571. ##  End of shell archive.
  1572. exit 0
  1573.